package com.program.services;

import com.program.controller.MainController;
import com.program.eneity.Airplane;
import com.program.eneity.Date;
import com.program.eneity.Runway;

import java.text.BreakIterator;

/**
 * @program: AirportSystem
 * @description: 跑道服务
 * @author: 19071027
 * @create: 2021-09-11 15:33
 **/
public class RunwayService {

    /**
     * 已入港航班
     */
    private int numEntered = 0;

    /**
     * 已离港航班
     */
    private int numLeft = 0;

    private static Runway runway1 = new Runway();

    private static Runway runway2 = new Runway();

    private static Runway runway3 = new Runway();

    private static Runway runway4 = new Runway();

    private static RunwayService runwayService = null;

    public int getNumEntered() {
        return numEntered;
    }

    public void setNumEntered(int numEntered) {
        this.numEntered = numEntered;
    }

    public int getNumLeft() {
        return numLeft;
    }

    public void setNumLeft(int numLeft) {
        this.numLeft = numLeft;
    }

    private RunwayService() {
        runway1.setAvailable(true);
        runway1.setType("Normal");

        runway2.setAvailable(true);
        runway2.setType("Normal");

        runway3.setAvailable(true);
        runway3.setType("Normal");

        runway4.setAvailable(true);
        runway4.setType("Emergency");
    }

    public static RunwayService getRunwayService() {
        if (runwayService == null) {
            synchronized (AirplaneService.class) {
                if (runwayService == null) {
                    runwayService = new RunwayService();
                }
            }
        }
        return runwayService;
    }

    public static Runway getRunway1() {
        return runway1;
    }

    public static Runway getRunway2() {
        return runway2;
    }

    public static Runway getRunway3() {
        return runway3;
    }

    public static Runway getRunway4() {
        return runway4;
    }


    /**
     * 分配降落跑道
     *
     * @param currentDate 当前时间
     * @return 延误时间 0-未延误
     */
    public String allocateLand(Date currentDate) {
        int lateMin = 0;
        String info = null;
        //发生延误的航班
        Airplane airplane;

        //分配着陆跑道
        if (!MainController.landPriorityQueue.isEmpty() && MainController.landPriorityQueue.peek() != null) {
            do {
                if (MainController.landPriorityQueue.peek().getFuel() <= 10 && RunwayService.getRunway4().isAvailable()) {
                    //    燃油小等于10 紧急情况 使用紧急跑道
                    runwayService.emergencyRunway(MainController.landPriorityQueue.peek());
                    //    分配紧急跑道成功
                    runway4.setAirplane(MainController.landPriorityQueue.peek());
                    lateMin = checkLateInfo(MainController.landPriorityQueue.peek(), currentDate);
                    if (lateMin != 0) {
                        airplane = MainController.landPriorityQueue.peek();
                        info = "因机场繁忙,航班" + airplane.getId() + "延误" + lateMin + "分钟" + airplane.stateInfo();
                    }
                    MainController.landPriorityQueue.remove();
                    numEntered++;
                }
                else {
                    //分配其它跑道
                    if (runwayService.normalRunway(MainController.landPriorityQueue.peek())) {
                        //分配其它跑道成功
                        lateMin = checkLateInfo(MainController.landPriorityQueue.peek(), currentDate);
                        if (lateMin != 0) {
                            airplane = MainController.landPriorityQueue.peek();
                            info = "因机场繁忙,航班" + airplane.getId() + "延误" + lateMin + "分钟" + airplane.stateInfo();
                        }

                        MainController.landPriorityQueue.remove();
                        numEntered++;
                    }
                    else {
                        //    分配其它跑道失败 继续等待
                        break;
                    }
                }
            }while (MainController.landPriorityQueue.peek().getFuel() <= 15);

        }
        return info;
    }

    /**
     * 分配起飞跑道
     *
     * @param currentDate 当前时间
     * @return 延误时间 0-未延误
     */
    public String allocateOff(Date currentDate) {
        int lateMin = 0;
        String info = null;
        //发生延误的航班
        Airplane airplane;

        //分配起飞跑道
        if (!MainController.offPriorityQueue.isEmpty() && MainController.offPriorityQueue.peek() != null) {
            if (runwayService.normalRunway(MainController.offPriorityQueue.peek())) {
                //    分配成功
                lateMin = checkLateInfo(MainController.offPriorityQueue.peek(), currentDate);
                if (lateMin != 0) {
                    airplane = MainController.offPriorityQueue.peek();
                    info = "因机场繁忙,航班" + airplane.getId() + "延误" + lateMin + "分钟" + airplane.stateInfo();
                }
                MainController.offPriorityQueue.remove();
                numLeft++;
            }
        }

        if (runwayService.isFull()) {
            //跑道已经全部被占用
            return "FULL";
        }

        return info;
    }


    /**
     * 常规跑道
     *
     * @param airplane
     * @return true-成功 false-失败
     */
    public boolean normalRunway(Airplane airplane) {
        Date releaseDate = getReleaseDate(MainController.date);
        if (runway1.isAvailable()) {
            runway1.setAvailable(false);
            runway1.setReleaseDate(releaseDate);
            runway1.setAirplane(airplane);
            return true;
        }
        else if (runway2.isAvailable()) {
            runway2.setAvailable(false);
            runway2.setReleaseDate(releaseDate);
            runway2.setAirplane(airplane);
            return true;
        }
        else if (runway3.isAvailable()) {
            runway3.setAvailable(false);
            runway3.setReleaseDate(releaseDate);
            runway3.setAirplane(airplane);
            return true;
        }
        else if (runway4.isAvailable()) {
            if (MainController.landPriorityQueue.peek() != null && MainController.landPriorityQueue.peek().getFuel() >= 15) {
                runway4.setAvailable(false);
                runway4.setReleaseDate(releaseDate);
                runway4.setAirplane(airplane);
                return true;
            }
        }
        return false;
    }

    /**
     * 使用紧急跑道
     *
     * @return true-成功 false-失败
     */
    public boolean emergencyRunway(Airplane airplane) {
        if (runway4.isAvailable()) {
            //使用紧急跑道
            runway4.setAvailable(false);
            runway4.setAirplane(airplane);
            Date releaseDate = getReleaseDate(MainController.date);
            runway4.setReleaseDate(releaseDate);
            return true;
        }

        return false;

    }

    /**
     * 释放占用的跑道资源
     *
     * @param currentDate 当前时间
     */
    public void release(Date currentDate) {
        if (runway1.getReleaseDate() != null && currentDate.getHour().equals(runway1.getReleaseDate().getHour()) && currentDate.getMinute().equals(runway1.getReleaseDate().getMinute())) {
            runway1.setAvailable(true);
            runway1.setReleaseDate(null);
            runway1.setAirplane(null);

        }
        if (runway2.getReleaseDate() != null && currentDate.getHour().equals(runway2.getReleaseDate().getHour()) && currentDate.getMinute().equals(runway2.getReleaseDate().getMinute())) {
            runway2.setAvailable(true);
            runway2.setReleaseDate(null);
            runway2.setAirplane(null);
        }
        if (runway3.getReleaseDate() != null && currentDate.getHour().equals(runway3.getReleaseDate().getHour()) && currentDate.getMinute().equals(runway3.getReleaseDate().getMinute())) {
            runway3.setAvailable(true);
            runway3.setReleaseDate(null);
            runway3.setAirplane(null);
        }
        if (runway4.getReleaseDate() != null && currentDate.getHour().equals(runway4.getReleaseDate().getHour()) && currentDate.getMinute().equals(runway4.getReleaseDate().getMinute())) {
            runway4.setAvailable(true);
            runway4.setReleaseDate(null);
            runway4.setAirplane(null);
        }
    }

    /**
     * 获取当前占用跑道释放资源的时间
     *
     * @param date 当前时间
     * @return 释放时间
     */
    public Date getReleaseDate(Date date) {
        Date releaseDate = new Date();
        EventService eventService = new EventService();
        int newMin = (Integer.valueOf(date.getMinute()) + eventService.getVirtualTime()) % 60;
        int newHour = (Integer.valueOf(date.getHour()) + ((Integer.valueOf(date.getMinute()) + eventService.getVirtualTime()) / 60)) % 24;
        if (newHour < 10) {
            releaseDate.setHour("0" + newHour);
        }
        else {
            releaseDate.setHour(String.valueOf(newHour));
        }

        if (newMin < 10) {
            releaseDate.setMinute("0" + newMin);
        }
        else {
            releaseDate.setMinute(String.valueOf(newMin));
        }

        return releaseDate;
    }

    /**
     * 判断跑道是否全满
     *
     * @return true-全满 false-未满
     */
    public boolean isFull() {
        if (runway1.isAvailable() || runway2.isAvailable() || runway3.isAvailable() || runway4.isAvailable()) {
            return false;
        }

        return true;
    }

    /**
     * 检查航班是否晚点
     *
     * @param airplane    航班
     * @param currentDate 当前时间
     * @return 晚点分钟数
     */


    public int checkLateInfo(Airplane airplane, Date currentDate) {
        //计划起飞/着陆时间
        Date scheduleTime = airplane.getDepartureTime() == null ? airplane.getLandingTime() : airplane.getDepartureTime();
        int scheduleHour = Integer.valueOf(scheduleTime.getHour());
        int scheduleMin = Integer.valueOf(scheduleTime.getMinute());
        int currentHour = Integer.valueOf(currentDate.getHour());
        int currentMin = Integer.valueOf(currentDate.getMinute());
        int delayMin = 0;
        if (currentHour == scheduleHour) {
            delayMin = currentMin - scheduleMin;
        }
        else if (currentHour > scheduleHour) {
            delayMin = (currentMin + 60) - scheduleMin;
        }
        return delayMin;
    }

    public boolean checkLongTimeWait() {
        Airplane offAirplane = MainController.offPriorityQueue.peek();
        Airplane landAirplane = MainController.landPriorityQueue.peek();
        int offLate = checkLateInfo(offAirplane, MainController.date);
        int landOff = checkLateInfo(landAirplane, MainController.date);
        if (offLate >= 5 && landOff < offLate) {
            return true;
        }
        return false;
    }

}
